Skip to content

9.10 批量操作

📝 模块更新日志 新特性*

+ 新增 `EFCore` 批量更新支持设置 `includePropertyNames` 和 `excludePropertyNames` 参数 4\.9\.2\.28 ⏱️2024\.04\.23 [c9926cc](https://gitee.com/dotnetchina/Furion/commit/c9926ccb6434316338816eaf259ae9191f40505e)

9.10.1 关于批量操作

Furion 框架中,默认只提供小数据(100 条 以内)批量数据操作,如果需要更大的数据批量处理,推荐使用第三方包 Zack.EFCore.Batch,支持和 Furion 无缝衔接。

9.10.2 Zack.EFCore.Batch 使用

EFCore 拦截器说明使用该第三方拓展库可能不会触发 EFCore 的拦截器,如 DbCommandInterceptorSaveChangesInterceptor

9.10.2.1 安装对应的数据库 NuGet

  • MSSQLZack.EFCore.Batch.MSSQL
  • MySqlZack.EFCore.Batch.MySQL.Pomelo
  • NpgsqlZack.EFCore.Batch.Npgsql
  • OracleZack.EFCore.Batch.Oracle
  • SqliteZack.EFCore.Batch.Sqlite

9.10.2.2 注册并配置服务

services.AddDatabaseAccessor(options =>  
{  
    options.AddDbPool<DefaultDbContext>(providerName: default, optionBuilder: (services, opt) => // 如果是 v3.7.11 之前,使用 opt =>  
    {  
        opt.UseBatchEF_Sqlite();    // SQlite 数据库包  
    });  
});  

9.10.2.3 基本使用

// 批量更新  
await repository.Context.BatchUpdate<Book>()  
    .Set(b => b.Price, b => b.Price + 3)  
    .Set(b => b.Title, b => s)  
    .Set(b => b.AuthorName,b=>b.Title.Substring(3,2)+b.AuthorName.ToUpper())  
    .Set(b => b.PubTime, b => DateTime.Now)  
    .Where(b => b.Id > n || b.AuthorName.StartsWith("Zack"))  
    .ExecuteAsync();  

// 批量删除  
await repository.Context.DeleteRangeAsync<Book>(b => b.Price > n || b.AuthorName == "zack yang");  

9.10.3 EFCore.BulkExtensions 使用

通过 NuGet 安装 EFCore.BulkExtensions 包即可。

9.10.3.1 常见批量操作

// 批量插入  
repository.Context.BulkInsert(entitiesList);  
repository.Context.BulkInsertAsync(entitiesList);  

// 批量更新  
repository.Context.BulkUpdate(entitiesList);  
repository.Context.BulkUpdateAsync(entitiesList);  

// 批量删除  
repository.Context.BulkDelete(entitiesList);  
repository.Context.BulkDeleteAsync(entitiesList);  

// 批量插入或更新  
repository.Context.BulkInsertOrUpdate(entitiesList);  
repository.Context.BulkInsertOrUpdateAsync(entitiesList);  

// 批量插入或更新或删除  
repository.Context.BulkInsertOrUpdateOrDelete(entitiesList);  
repository.Context.BulkInsertOrUpdateOrDeleteAsync(entitiesList);  

// 批量读取多个实体  
repository.Context.BulkRead(entitiesList);  
repository.Context.BulkReadAsync(entitiesList);  

// 批量清空表(慎用!!!!!)  
repository.Context.Truncate<Entity>();  
repository.Context.TruncateAsync<Entity>();  

9.10.3.2 查询后批量操作

// 根据条件批量删除  
repository.Where(a => a.ItemId >  500).BatchDelete();  
await repository.Where(a => a.ItemId >  500).BatchDeleteAsync();  

// 根据条件批量更新  
repository.Where(a => a.ItemId <= 500).BatchUpdate(a => new Item { Quantity = a.Quantity + 100 });  
repository.Where(a => a.ItemId <= 500).BatchUpdate(new Item { Description = "Updated" });  
await repository.Where(a => a.ItemId <= 500).BatchUpdateAsync(new Item { Description = "Updated" });  

// 批量更新指定列  
var updateColumns = new List<string> { nameof(Item.Quantity) };  
var q = repository.Where(a => a.ItemId <= 500);  
int affected = q.BatchUpdate(new Item { Description = "Updated" }, updateColumns);  

9.10.3.3 批量操作性能

Operations\Rows 100,000 EF 100,000 EFBulk 1,000,000 EFBulk
Insert 38.98 s 2.10 s 17.99 s
Update 109.25 s 3.96 s 31.45 s
Delete 7.26 s 2.04 s 12.18 s
----------------- ------------ ---------------- ------------------
Together 70.70 s 5.88 s 56.84 s

9.10.4 EFCore 7 内置批量操作

非微软支持数据库适配问题如果使用的是非微软支持的数据库,如 OracleMySQLPostgreSQL 等,可能适配 EFCore 7 不及时会出现找不到方法异常。

https://docs.microsoft.com/zh-cn/ef/core/what-is-new/ef-core-7.0/whatsnew#executeupdate-and-executedelete-bulk-updates

// 批量删除  
await repository.Entities.ExecuteDeleteAsync();  
await repository.Entities.Where(t => t.Text.Contains(".NET")).ExecuteDeleteAsync();  
await repository.Entities.Where(t => t.Posts.All(e => e.PublishedOn.Year < 2022)).ExecuteDeleteAsync();  

// 批量更新  
await repository.Entities.ExecuteUpdateAsync(  
    s => s.SetProperty(b => b.Name, b => b.Name + " *Featured!*"));  

await repository.Entities  
    .Where(p => p.PublishedOn.Year < 2022)  
    .ExecuteUpdateAsync(s => s  
        .SetProperty(b => b.Title, b => b.Title + " (" + b.PublishedOn.Year + ")")  
        .SetProperty(b => b.Content, b => b.Content + " ( This content was published in " + b.PublishedOn.Year + ")"));  

await repository.Entities  
    .Where(t => t.Posts.All(e => e.PublishedOn.Year < 2022))  
    .ExecuteUpdateAsync(s => s.SetProperty(t => t.Text, t => t.Text + " (old)"));  

9.10.5 批量更新包含或排除列 ✨

版本说明以下内容仅限 Furion 4.9.2.28 + 版本使用。

var entities = new List<Person> { ... };    

// 更新指定列    
repository.Update(entities, includePropertyNames: new string[] { nameof(Person.Name), nameof(Person.Age) });    

// 或者排除指定列    
repository.Update(entities, excludePropertyNames: new string[] { nameof(Person.Address) });  

9.10.6 反馈与建议

与我们交流给 Furion 提 Issue


了解更多想了解更多 EFCore.BulkExtensions 知识可查阅 EFCore.BulkExtensions 开源仓库